home *** CD-ROM | disk | FTP | other *** search
/ Ham Radio 2000 #1 / Ham Radio 2000.iso / ham2000 / tcp_ip / wnos / wn941101 / pop2cli.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-10-08  |  9.0 KB  |  385 lines

  1. /*
  2.  *    POP2 Client routines.  Originally authored by Mike Stockett
  3.  *      (WA7DYX).
  4.  *    Modified 12 May 1991 by Mark Edwards (WA6SMN) to use new timer
  5.  *    facilities in NOS0423.  Fixed type mismatches spotted by C++.
  6.  *    Modified 27 May 1990 by Allen Gwinn (N5CKP) for compatibility
  7.  *      with later releases (NOS0522).
  8.  *    Added into NOS by PA0GRI (and linted into "standard" C)
  9.  *
  10.  *    Some code culled from previous releases of SMTP.
  11.  *
  12.  *    Client routines for Simple Mail Transfer Protocol ala RFC821
  13.  *    A.D. Barksdale Garbee II, aka Bdale, N3EUA
  14.  *    Copyright 1986 Bdale Garbee, All Rights Reserved.
  15.  *    Permission granted for non-commercial copying and use, provided
  16.  *      this notice is retained.
  17.  *     Modified 14 June 1987 by P. Karn for symbolic target addresses,
  18.  *      also rebuilt locking mechanism
  19.  *    Copyright 1987 1988 David Trulli, All Rights Reserved.
  20.  *    Permission granted for non-commercial copying and use, provided
  21.  *    this notice is retained.
  22.  */
  23. #include <stdio.h>
  24. #include <fcntl.h>
  25. #include <time.h>
  26. #include <setjmp.h>
  27. #ifdef UNIX
  28. #include <sys/types.h>
  29. #endif
  30. #ifdef    __TURBOC__
  31. #include <dir.h>
  32. #include <io.h>
  33. #endif
  34. #include "global.h"
  35. #include "config.h"
  36.  
  37. #ifdef POP2_CLIENT
  38. #ifdef    ANSIPROTO
  39. #include <stdarg.h>
  40. #endif
  41. #include "mbuf.h"
  42. #include "cmdparse.h"
  43. #include "proc.h"
  44. #include "socket.h"
  45. #include "timer.h"
  46. #include "netuser.h"
  47. #include "dirutil.h"
  48. #include "files.h"
  49. #include "smtp.h"
  50.  
  51. #define BUF_LEN        257
  52.  
  53. /* mail separator */
  54. #define isNotSOM(x)        ((strncmp(x,"From ",5) != 0))
  55.  
  56. /* POP client control block */
  57. static struct pop_ccb {
  58.     int  socket;        /* socket for this connection */
  59.     char state;        /* client state */
  60. #define       CALL        0
  61. #define       NMBR        3
  62. #define       SIZE        5
  63. #define       XFER        8
  64. #define       EXIT        10
  65.     char buf[BUF_LEN];    /* tcp input buffer pointer */
  66.     char count;        /* input buffer length */
  67.     int  folder_len;    /* number of msgs in current folder */
  68.     long msg_len;        /* length of current msg */
  69.     int  msg_num;        /* current message number */
  70. } *ccb;
  71. #define NULLCCB        (struct pop_ccb *)0
  72.  
  73. static int16 Popquiet = 0;
  74. static int32 mailhost = 0;
  75.  
  76. static void pop_send __ARGS((int unused,void *cb1,void *p));
  77. static int poptick __ARGS((void));
  78. static FILE *fd;
  79.  
  80. /* Command string specifications */
  81. static char near mailbox_name[20],
  82.      username[20],
  83.      password[20],
  84.      Workfile_name[] ="mbox.pop",
  85.      ackd_cmd[]      = "ACKD\n",
  86. #ifdef POP_FOLDERS
  87.      fold_cmd[]      = "FOLD %s\n",
  88. #endif
  89.      login_cmd[]      = "HELO %s %s\n",
  90. /*      nack_cmd[]      = "NACK\n",         /* Not implemented */
  91.      quit_cmd[]      = "QUIT\n",
  92.      read_cur_cmd[]  = "READ\n",
  93.      retr_cmd[]      = "RETR\n",
  94.      greeting_rsp[]  = "+ POP2 ";    /* Response string keys */
  95. /*     ok_rsp[]        = "+ OK";    */
  96.  
  97. static int
  98. domailbox(argc,argv,p)
  99. int argc;
  100. char *argv[];
  101. void *p;
  102. {
  103.     if(argc < 2 && mailbox_name[0] != '\0')
  104.         tprintf("%s\n",mailbox_name);
  105.     else {
  106.         sprintf(mailbox_name,"%.18s",argv[1]);
  107.     }
  108.     return 0;
  109. }
  110.  
  111. static int
  112. domailhost(argc,argv,p)
  113. int argc;
  114. char *argv[];
  115. void *p;
  116. {
  117.     int32 n;
  118.  
  119.     if(argc < 2) {
  120.         tprintf("%s\n",inet_ntoa(mailhost));
  121.     } else {
  122.         if((n = resolve(argv[1])) == 0) {
  123.             tprintf(Badhost,argv[1]);
  124.             return 1;
  125.         } else {
  126.             mailhost = n;
  127.         }
  128.     }
  129.     return 0;
  130. }
  131.  
  132. static int
  133. popkick(argc,argv,p)
  134. int argc;
  135. char *argv[];
  136. void *p;
  137. {
  138.     return (poptick());
  139. }
  140.  
  141. static int
  142. doquiet(argc,argv,p)
  143. int argc;
  144. char *argv[];
  145. void *p;
  146. {
  147.     return setintrc(&Popquiet,"POP2 quiet",argc,argv,0,3);
  148. }
  149.  
  150. static struct timer popcli_t;
  151.  
  152. static int
  153. dotimer(argc,argv,p)
  154. int argc;
  155. char *argv[];
  156. void *p;
  157. {
  158.     if(argc < 2) {
  159.         tprintf("POP2 timer %lu/%lu s\n",
  160.             read_timer(&popcli_t)/1000L,dur_timer(&popcli_t)/1000L);
  161.     } else {
  162.         stop_timer(&popcli_t);
  163.         popcli_t.func = (void (*)())poptick;          /* what to call on timeout */
  164.         popcli_t.arg = NULLCHAR;                    /* dummy value */
  165.         set_timer(&popcli_t,atol(argv[1])*1000L);     /* set timer duration */
  166.         start_timer(&popcli_t);                        /* and fire it up */
  167.     }
  168.     return 0;
  169. }
  170.  
  171. static int
  172. douserdata(argc,argv,p)
  173. int argc;
  174. char *argv[];
  175. void *p;
  176. {
  177.     if (argc < 2 && username[0] != '\0')
  178.         tprintf("%s\n",username);
  179.     else if (argc != 3) {
  180.         tputs("Usage: pop2 userdata <username> <password>\n");
  181.         return 1;
  182.     } else {
  183.         sprintf(username,"%.18s",argv[1]);
  184.         sprintf(password,"%.18s",argv[2]);
  185.     }
  186.     return 0;
  187. }
  188.  
  189. int
  190. dopop2(int argc,char *argv[],void *p) {
  191.   struct cmds Popcmds[] = {
  192.       "mailbox",    domailbox,    0,    0,    NULLCHAR,
  193.       "mailhost",    domailhost,    0,    0,    NULLCHAR,
  194.       "kick",    popkick,    0,    0,    NULLCHAR,
  195.       "quiet",    doquiet,    0,    0,    NULLCHAR,
  196.       "timer",    dotimer,    0,    0,    NULLCHAR,
  197.       "userdata",    douserdata,    0,    0,    NULLCHAR,
  198.       NULLCHAR,
  199.   };
  200.   return subcmd(Popcmds,argc,argv,p);
  201. }
  202.  
  203. static int
  204. poptick()
  205. {
  206.     int error = 0;
  207.  
  208.     if (ccb == NULLCCB) {
  209.         /* Don't start if any of the required parameters have not been specified */
  210.         if (mailhost == 0) {
  211.             tputs("POP2 Mailhost not set\n");
  212.             error = 1;
  213.         }
  214.         if (mailbox_name[0] == '\0') {
  215.             tputs("POP2 Mailbox not set\n");
  216.             error = 1;
  217.         }
  218.         if (username[0] == '\0' || password[0] == '\0') {
  219.             tputs("POP2 Username and/or password not set\n");
  220.             error = 1;
  221.         }
  222.         if(error == 0) {
  223.             if ((ccb = (struct pop_ccb *)mxallocw(sizeof(struct pop_ccb))) == NULLCCB) {
  224.                 tputs("Unable to allocate CCB\n");
  225.                 error = 1;
  226.             } else {
  227.                 stop_timer(&popcli_t);
  228.                 newproc("POP2 Client",1024,pop_send,0,ccb,NULL,0);
  229.             }
  230.         }
  231.     } else {
  232.         start_timer(&popcli_t);
  233.     }
  234.     return error;
  235. }
  236.  
  237. static void
  238. pop_send(unused,cb1,p)
  239. int unused;
  240. void *cb1;
  241. void *p;
  242. {
  243.     struct sockaddr_in fsocket;
  244.     FILE *mf;
  245.     char mailbox_pathname[BUF_LEN];
  246.  
  247.     fsocket.sin_family = AF_INET;
  248.     fsocket.sin_addr.s_addr = mailhost;
  249.     fsocket.sin_port = IPPORT_POP2;
  250.  
  251.     ccb->socket = socket(AF_INET,SOCK_STREAM,0);
  252.     sockmode(ccb->socket,SOCK_ASCII);
  253.  
  254.     if (connect(ccb->socket,(char *)&fsocket,SOCKSIZE) != -1) {
  255.       log(ccb->socket,"POP2  connect");
  256.       ccb->state = CALL;
  257.       for(;;) {
  258. loop:
  259.         if(ccb->state == EXIT) {
  260.           usprintf(ccb->socket,quit_cmd);
  261.           break;
  262.         }
  263.         if (recvline(ccb->socket,ccb->buf,BUF_LEN) == -1)
  264.           break;
  265.         rip(ccb->buf);
  266.         switch(ccb->state) {
  267.         case CALL:
  268.           if (strncmp(ccb->buf,greeting_rsp,strlen(greeting_rsp)) == 0) {
  269.         usprintf(ccb->socket,login_cmd,username,password);
  270.         ccb->state = NMBR;
  271.           } else {
  272.         ccb->state = EXIT;
  273.           }
  274.           goto loop;
  275.  
  276.         case NMBR:
  277.           switch (ccb->buf[0]) {
  278.           case '#':
  279.         ccb->folder_len = atoi(&(ccb->buf[1]));
  280.         usprintf(ccb->socket,read_cur_cmd);
  281.         ccb->state = SIZE;
  282.         goto loop;
  283.           case '+':
  284.         /* If there is no mail (the only time we get a "+"
  285.          * response back at this stage of the game),
  286.          * then just close out the connection, because
  287.          * there is nothing more to do!! */
  288.           default:
  289.         ccb->state = EXIT;
  290.           }
  291.           goto loop;
  292.  
  293.         case SIZE:
  294.           if (ccb->buf[0] == '=') {
  295.         ccb->msg_len = atol(&(ccb->buf[1]));
  296.         if (ccb->msg_len > 0) {
  297.           usprintf(ccb->socket,retr_cmd);
  298.           ccb->state = XFER;
  299.           if ((fd = open_file(Workfile_name,"a+",0,1)) == NULLFILE) {
  300.             ccb->state = EXIT;
  301.             goto loop;
  302.           }
  303.           fseek(fd,0,SEEK_SET);
  304.         } else {
  305.           ccb->state = EXIT;
  306.         }
  307.           } else
  308.         ccb->state = EXIT;
  309.           goto loop;
  310.  
  311.         case XFER:
  312.           fprintf(fd,"%s\n",ccb->buf);
  313.           /* Add CRLF */
  314.           if((ccb->msg_len -= (long)(strlen(ccb->buf)+2)) > 0)
  315.         goto loop;
  316.           /* All done, so do local cleanup */
  317.           if (mlock(Mailspool,mailbox_name)) {
  318.         tprintf("Can't open mailbox, new mail in file %s\n",
  319.              Workfile_name);
  320.         ccb->state = EXIT;
  321.         goto loop;
  322.           }
  323.           sprintf(mailbox_pathname,"%s/%s.txt",Mailspool,mailbox_name);
  324.           mf = open_file(mailbox_pathname,"a+",0,1);
  325.           if(mf == NULLFILE) {
  326.         ccb->state = EXIT;
  327.         goto loop;
  328.           }
  329.           fseek(fd,0,SEEK_SET);
  330.  
  331.           /* get first line */
  332.           if (fgets(ccb->buf,BUF_LEN,fd) != NULLCHAR) {
  333.         /* if pop server is not NOS then insert SOM */
  334.         if (isNotSOM(&ccb->buf[0])) {
  335.           char tmp[BUF_LEN];
  336.           sprintf(tmp,"From POP2@%s at %s",
  337.               inet_ntoa(mailhost),ptime(&currtime));
  338.           fputs(tmp,mf);
  339.         }
  340.         /* copy all */
  341.         fputs(ccb->buf,mf);
  342.         while (!feof(fd)) {
  343.           if(fgets(ccb->buf,BUF_LEN,fd) != NULLCHAR) {
  344.             fputs(ccb->buf,mf);
  345.           }
  346.         }
  347.           }
  348.           fclose(mf);
  349.           fclose(fd);
  350.           fd = NULL;
  351.           rmlock(Mailspool,mailbox_name);
  352.           unlink(Workfile_name);
  353.           usprintf(ccb->socket,ackd_cmd);
  354.           if(Popquiet < 2)
  355.         tprintf("New mail for %s from mailhost <%s> at %s%s",
  356.              mailbox_name, inet_ntoa(mailhost),
  357.              ctime(&currtime), (Popquiet < 1) ? "\007" : "");
  358.  
  359.           if(Popquiet == 3)
  360.         log(ccb->socket,"POP2  new mail <%s>",inet_ntoa(mailhost));
  361.  
  362.           ccb->msg_num++;
  363.           ccb->state = SIZE;
  364.           goto loop;
  365.  
  366.         case EXIT:
  367.           if (fd != NULLFILE)
  368.         fclose(fd);
  369.         default:
  370.           goto loop;
  371.         }
  372.       }
  373.     }
  374.     if (fd != NULLFILE)
  375.       fclose(fd);
  376.     recvline(ccb->socket,ccb->buf,BUF_LEN);
  377.     close_s(ccb->socket);
  378.     xfree((char *)ccb);
  379.     ccb = NULLCCB;
  380.     start_timer(&popcli_t);
  381.     return;
  382. }
  383.  
  384. #endif /* POP2_CLIENT */
  385.